<html lang="en">

<head>
    <meta charset="utf-8">
    <title>ncnn webassembly yolov5 camera</title>
    <style>
        video {
            position: absolute;
            visibility: hidden;
        }
        canvas {
            border: 1px solid black;
        }
    </style>

</head>

<body>
    <div>
        <h1>ncnn webassembly yolov5 camera</h1>
        <video id="video"></video>
        <div>
            <canvas id="canvas" width="640"></canvas>
        </div>
    </div>

    <script type='text/javascript'>
        var Module = {};
        if (typeof SharedArrayBuffer === 'undefined') {
            fetch('yolov5up.wasm')
            .then(response => response.arrayBuffer())
            .then(buffer => {
                Module.wasmBinary = buffer;
                var script = document.createElement('script');
                script.src = 'yolov5up.js';
                script.onload = function() {
                    console.log('Emscripten boilerplate loaded.');
                }
                document.body.appendChild(script);
            });
        }
        else {
            fetch('yolov5.wasm')
            .then(response => response.arrayBuffer())
            .then(buffer => {
                Module.wasmBinary = buffer;
                var script = document.createElement('script');
                script.src = 'yolov5.js';
                script.onload = function() {
                    console.log('Emscripten boilerplate loaded.');
                }
                document.body.appendChild(script);
            });
        }

        var dst = null;
        var resultarray = null;
        var resultbuffer = null;
        window.addEventListener('DOMContentLoaded', function() {
            var isStreaming = false;
            video = document.getElementById('video');
            canvas = document.getElementById('canvas');
            ctx = canvas.getContext('2d');
            w = 640;
            h = 480;
            var constraints = { audio: false, video: { width: w, height: h } };
            navigator.mediaDevices.getUserMedia(constraints)
                .then(function(mediaStream) {
                    var video = document.querySelector('video');
                    video.srcObject = mediaStream;
                    video.onloadedmetadata = function(e) {
                        video.play();
                    };
                })
                .catch(function(err) {
                    console.log(err.message);
                });
            // Wait until the video stream canvas play
            video.addEventListener('canplay', function(e) {
                if (!isStreaming) {
                    // videoWidth isn't always set correctly in all browsers
                    if (video.videoWidth > 0) h = video.videoHeight / (video.videoWidth / w);
                    canvas.setAttribute('width', w);
                    canvas.setAttribute('height', h);
                    isStreaming = true;
                }
            }, false);

            // Wait for the video to start to play
            video.addEventListener('play', function() {
                //Setup image memory
                var id = ctx.getImageData(0, 0, canvas.width, canvas.height);
                var d = id.data;
                dst = _malloc(d.length);

                // max 20 objects
                resultarray = new Float32Array(6 * 20);
                resultbuffer = _malloc(6 * 20 * Float32Array.BYTES_PER_ELEMENT);

                HEAPF32.set(resultarray, resultbuffer / Float32Array.BYTES_PER_ELEMENT);

                //console.log("What " + d.length);

                sFilter();
            });

        });

        var class_names = [
            "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
            "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
            "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
            "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
            "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
            "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
            "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
            "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
            "hair drier", "toothbrush"
        ];

        var colors = [
            "rgb( 54,  67, 244)",
            "rgb( 99,  30, 233)",
            "rgb(176,  39, 156)",
            "rgb(183,  58, 103)",
            "rgb(181,  81,  63)",
            "rgb(243, 150,  33)",
            "rgb(244, 169,   3)",
            "rgb(212, 188,   0)",
            "rgb(136, 150,   0)",
            "rgb( 80, 175,  76)",
            "rgb( 74, 195, 139)",
            "rgb( 57, 220, 205)",
            "rgb( 59, 235, 255)",
            "rgb(  7, 193, 255)",
            "rgb(  0, 152, 255)",
            "rgb( 34,  87, 255)",
            "rgb( 72,  85, 121)",
            "rgb(158, 158, 158)",
            "rgb(139, 125,  96)"
        ];

        function ncnn_yolov5() {
            var canvas = document.getElementById('canvas');
            var ctx = canvas.getContext('2d');

            var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            var data = imageData.data;

            HEAPU8.set(data, dst);

            _yolov5_ncnn(dst, canvas.width, canvas.height, resultbuffer);

            // resultarray
            var qaqarray = HEAPF32.subarray(resultbuffer / Float32Array.BYTES_PER_ELEMENT, resultbuffer / Float32Array.BYTES_PER_ELEMENT + 6 * 20);

            var i;
            for (i = 0; i < 20; i++) {
                var label = qaqarray[i * 6 + 0];
                var prob = qaqarray[i * 6 + 1];
                var bbox_x = qaqarray[i * 6 + 2];
                var bbox_y = qaqarray[i * 6 + 3];
                var bbox_w = qaqarray[i * 6 + 4];
                var bbox_h = qaqarray[i * 6 + 5];

                if (label == -233)
                    continue;

                console.log('qaq ' + label + ' = ' + prob);

                ctx.strokeStyle = colors[i % 19];
                ctx.strokeRect(bbox_x, bbox_y, bbox_w, bbox_h);

                var text = class_names[label] + " = " + parseFloat(prob * 100).toFixed(2) + "%";

                ctx.textBaseline = 'top';
                var text_width = ctx.measureText(text).width;
                var text_height = parseInt(ctx.font, 10);

                var x = bbox_x;
                var y = bbox_y - text_height;
                if (y < 0)
                    y = 0;
                if (x + text_width > canvas.width)
                    x = canvas.width - text_width;

                ctx.fillStyle = "rgb(255,255,255)";
                ctx.fillRect(x, y, text_width, text_height);
                ctx.fillStyle = "rgb(0,0,0)";
                ctx.fillText(text, x, y);
            }
        }

        //Request Animation Frame function
        var sFilter = function() {
            if (video.paused || video.ended) return;

            ctx.fillRect(0, 0, w, h);
            ctx.drawImage(video, 0, 0, w, h);

            ncnn_yolov5();

            window.requestAnimationFrame(sFilter);
        }

    </script>

</body>

</html>
